package com.sh.rbac.utils;

import com.sh.rbac.domain.entity.Job;
import com.sh.rbac.exception.CustomException;
import com.sh.rbac.result.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;

import java.util.Date;

/**
 * 定时任务工具类
 *
 * @author wb
 * @since 2024-08-06
 */

@Slf4j
public class TaskUtils {

    // 获取 JobKey
    public static JobKey getJobKey(Job job) {
        return JobKey.jobKey(job.getJobName(), job.getJobGroup());
    }

    // 获取 TriggerKey
    public static TriggerKey getTriggerKey(Job job) {
        return TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
    }

    @SuppressWarnings("unchecked")
    public static void createJob(Job job, Scheduler scheduler) {
        if(!isValidExpression(job.getCronExpression())){
            throw new CustomException(ResultCodeEnum.CRON_ERROR);
        }

        try {
            // 获取任务键
            JobKey jobKey = getJobKey(job);

            // 获取任务类
            Class<org.quartz.Job> jobClass = (Class<org.quartz.Job>) Class.forName(job.getInvokeTarget());

            // 构建任务
            JobDetail jobDetail = JobBuilder
                    .newJob(jobClass)
                    .withIdentity(jobKey)
                    .withIdentity(job.getJobName(), job.getJobGroup())
                    .withDescription(job.getJobName())
                    .build();

            // 获取触发器键
            TriggerKey triggerKey = getTriggerKey(job);


            // 表达式调度构建器
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);

            // 创建触发器
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(cronScheduleBuilder)
                    .build();

            // 判断任务是否存在
            if (scheduler.checkExists(jobKey)) {
                scheduler.deleteJob(jobKey);
            }

            // 添加任务
            scheduler.scheduleJob(jobDetail, trigger);

            // 如果任务状态为暂停，则暂停任务
            if (job.getStatus().equals(1)) {
                scheduler.pauseJob(jobKey);
            }

        } catch (ClassNotFoundException e) {
            throw new CustomException(ResultCodeEnum.CLASS_NOT_FIND);
        }catch (Exception e) {
            throw new CustomException(e.getMessage());
        }
    }

    /**
     * 设置定时策略
     */
    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(Job job, CronScheduleBuilder cb) throws Exception {
        return switch (job.getMisfirePolicy()) {
            // 立即执行
            case 1 -> cb.withMisfireHandlingInstructionIgnoreMisfires();
            // 执行一次
            case 2 -> cb.withMisfireHandlingInstructionFireAndProceed();
            // 放弃执行
            case 3 -> cb.withMisfireHandlingInstructionDoNothing();
            default ->
                    throw new Exception("The task misfire policy '" + job.getMisfirePolicy() + "' cannot be used in cron schedule tasks");
        };
    }

    /**
     * 获取任务下一次执行时间
     *
     * @param corn corn表达式
     * @return 下次执行时间
     */
    public static Date getNextJobExecutionDate(String corn) {
        try {
            CronExpression cronExpression = new CronExpression("0 0/15 * * * ?");
            return cronExpression.getNextInvalidTimeAfter(new Date());
        } catch (Exception e) {
            throw new CustomException("获取任务下一次执行时间失败, 错误信息: " + e.getMessage());
        }
    }

    /**
     * 校验 cron 是否有效
     *
     * @param cronExpression cron 表达式
     * @return 是否有效
     */
    public static boolean isValidExpression(String cronExpression) {
        try {
            new CronExpression(cronExpression);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

}
